package com.nado.extensions.data;

import org.w3c.dom.Node;

import java.util.List;

/**
 * 환경 정보 모델에 대한 사용자 뷰를 제공하는 데이터 액세스 인터페이스.
 * <p/>
 * 임의의 소스로부터 생성된 환경 정보 데이터는 Tree 구조로 되어 있다. DataHandler는 이러한
 * Tree를 구성하는 각 노드와 하위 노드들에 대한 access/search/evaluation 인터페이스를 정의한다.
 * <p/>
 * 각 API에서 파라미터로 넘겨지는 key 값의 의미는 각 구현체마다 다를 수 있다. 가장 일반적으로 사용하는
 * DOM Type DataHandler({@link Dom4jXmlDataHandler})의 경우 이 값은 XPath 표현식을 의미한다.
 *
 * @see Dom4jXmlDataHandler
 */
public interface DataHandler {

	/**
	 * 등록된 DataHandler 를 외부에서 참조하기 위한 이름을 반환하며, 등록되어 있지 않은 경우는 null을 반환한다.
	 *
	 * @return reference name
	 * @see DataHandlerFactory#getDataHandler(String)
	 */
	String getHandlerName();

	/**
	 * 파일에서 생성된 DataHandler의 경우 파일 위치를 반환하며, 그렇지 않은 경우 null을 반환한다.
	 *
	 * @return file name
	 */
	String getLocation();

	/**
	 * 현재 노드에서 파라미터로 지정된 상대 경로에 해당하는 노드의 {@link DataHandler}를 반환한다.
	 * 해당 경로에 여러 개의 노드가 존재하는 경우 첫번째 노드에 해당하는 {@link DataHandler}를 반환한다.
	 * 존재하지 않는 경우 null을 반환한다.
	 *
	 * @return DataHandler
	 */
	DataHandler peek(String key);

	/**
	 * 현재 노드에서 파라미터로 지정된 상대 경로에 해당하는 노드의 {@link DataHandler}를 List 형태로 반환한다.
	 * 해당 경로에 값이 존재하지 않는 경우 Collections.emptyList()를 반환한다.
	 *
	 * @return List of DataHandler
	 */
	List<DataHandler> peekAll(String key);

	/**
	 * 현재 노드의 하위 노드 중 {@link Node#ELEMENT_NODE} Type의 {@link DataHandler}를 List 형태로 반환한다.
	 * 하위 Element 가 없는 경우 Collections.emptyList()를 반환한다.
	 *
	 * @return List of DataHandler
	 */
	List<DataHandler> peekChildren();

	/**
	 * 현재 노드에서 파라미터로 지정된 상대 경로에 해당하는 노드의 {@link DataHandler}를 반환한다.
	 * 해당 경로에 여러 개의 노드가 존재하는 경우 첫 번째 노드에 해당하는 {@link DataHandler}를 반환한다.
	 *
	 * @return DataHandler
	 * @throws DataHandlerException 키에 해당하는 sub node가 존재하지 않을 경우
	 */
	DataHandler select(String key) throws DataHandlerException;

	/**
	 * 현재 노드에서 파라미터로 지정된 상대 경로에 해당하는 노드의 {@link DataHandler}를 List 형태로 반환한다.
	 *
	 * @return List of DataHandler
	 * @throws DataHandlerException 키에 해당하는 sub node가 존재하지 않을 경우
	 */
	List<DataHandler> selectAll(String key) throws DataHandlerException;

	/**
	 * 현재 노드의 하위 노드 중 {@link Node#ELEMENT_NODE} Type의 {@link DataHandler}를 List 형태로 반환한다.
	 * 하위 Element 가 없는 경우 Collections.emptyList()를 반환한다.
	 *
	 * @return List of DataHandler
	 * @throws DataHandlerException 키에 해당하는 sub node가 존재하지 않을 경우
	 */
	List<DataHandler> selectChildren() throws DataHandlerException;

	/**
	 * @deprecated use {@link #peek(String)}
	 */
	DataHandler subConfig(String key);

	/**
	 * @deprecated use {@link #select(String)}
	 */
	DataHandler subconfig(String key) throws DataHandlerException;

	/**
	 * @deprecated use {@link #selectAll(String)}
	 */
	List<DataHandler> subConfigs(String key) throws DataHandlerException;

	/**
	 * @deprecated use {@link #peekAll(String)}
	 */
	List<DataHandler> sublists(String path);

	/**
	 * @deprecated use {@link #selectChildren()}
	 */
	List<DataHandler> childConfigs() throws DataHandlerException;

	/**
	 * 현재 요소의 이름을 반환한다.
	 */
	String getRootName();

	/**
	 * 지정된 경로가 존재하는지 확인한다.
	 */
	boolean containsKey(String key);

	/**
	 * 현재 노드에서 파라미터로 지정된 상대 경로에 해당하는 노드의 String 값을 반환한다.
	 *
	 * @throws DataHandlerException 경로에 해당하는 node가 존재하지 않을 경우
	 */
	String get(String key) throws DataHandlerException;

	/**
	 * 현재 노드에서 파라미터로 지정된 상대 경로에 해당하는 노드의 값을 String 형태로 반환한다.
	 * 해당 경로에 값이 존재하지 않는 경우 {@code defaultValue}를 반환한다.
	 */
	String get(String key, String defaultValue);

	/**
	 * {@link #get}을 통해 검색한 경로의 값을 {@code boolean} Type으로 변환해서 반환한다.
	 *
	 * @throws DataHandlerException 경로에 해당하는 node가 존재하지 않을 경우
	 */
	boolean getBoolean(String key) throws DataHandlerException;

	/**
	 * {@link #get}을 통해 검색한 경로의 값을 {@code boolean} Type으로 변환해서 반환한다.
	 * 해당 경로에 값이 존재하지 않는 경우 {@code defaultValue}를 반환한다.
	 */
	boolean getBoolean(String key, boolean defaultValue);

	/**
	 * {@link #get}을 통해 검색한 경로의 값을 {@code int} Type으로 변환해서 반환한다.
	 *
	 * @throws NumberFormatException 경로에 해당하는 node 값의 포맷이 적절하지 않은 경우
	 * @throws DataHandlerException  경로에 해당하는 node가 존재하지 않을 경우
	 */
	int getInt(String key) throws NumberFormatException, DataHandlerException;

	/**
	 * {@link #get}을 통해 검색한 경로의 값을 {@code int} Type으로 변환해서 반환한다.
	 * 해당 경로에 값이 존재하지 않는 경우 {@code defaultValue}를 반환한다.
	 *
	 * @throws NumberFormatException 경로에 해당하는 node 값의 포맷이 적절하지 않은 경우
	 */
	int getInt(String key, int defaultValue) throws NumberFormatException;

	/**
	 * {@link #get}을 통해 검색한 경로의 값을 {@code double} Type으로 변환해서 반환한다.
	 *
	 * @throws NumberFormatException 경로에 해당하는 node 값의 포맷이 적절하지 않은 경우
	 * @throws DataHandlerException  경로에 해당하는 node가 존재하지 않을 경우
	 */
	double getDouble(String key) throws NumberFormatException, DataHandlerException;

	/**
	 * {@link #get}을 통해 검색한 경로의 값을 {@code double} Type으로 변환해서 반환한다.
	 * 해당 경로에 값이 존재하지 않는 경우 {@code defaultValue}를 반환한다.
	 *
	 * @throws NumberFormatException 경로에 해당하는 node 값의 포맷이 적절하지 않은 경우
	 */
	double getDouble(String key, double defaultValue) throws NumberFormatException;

	/**
	 * {@link #get}을 통해 검색한 경로의 값을 {@code long} Type으로 변환해서 반환한다.
	 *
	 * @throws NumberFormatException 경로에 해당하는 node 값의 포맷이 적절하지 않은 경우
	 * @throws DataHandlerException  경로에 해당하는 node가 존재하지 않을 경우
	 */
	long getLong(String key) throws NumberFormatException, DataHandlerException;

	/**
	 * {@link #get}을 통해 검색한 경로의 값을 {@code long} Type으로 변환해서 반환한다.
	 * 해당 경로에 값이 존재하지 않는 경우 {@code defaultValue}를 반환한다.
	 *
	 * @throws NumberFormatException 경로에 해당하는 node 값의 포맷이 적절하지 않은 경우
	 */
	long getLong(String key, long defaultValue) throws NumberFormatException;

	/**
	 * {@link #get}을 통해 검색한 경로의 값을 {@code float} Type으로 변환해서 반환한다.
	 *
	 * @throws NumberFormatException 경로에 해당하는 node 값의 포맷이 적절하지 않은 경우
	 * @throws DataHandlerException  경로에 해당하는 node가 존재하지 않을 경우
	 */
	float getFloat(String key) throws NumberFormatException, DataHandlerException;

	/**
	 * {@link #get}을 통해 검색한 경로의 값을 {@code float} Type으로 변환해서 반환한다.
	 * 해당 경로에 값이 존재하지 않는 경우 {@code defaultValue}를 반환한다.
	 *
	 * @throws NumberFormatException 경로에 해당하는 node 값의 포맷이 적절하지 않은 경우
	 */
	float getFloat(String key, float defaultValue) throws NumberFormatException;

	/**
	 * 경로에 존재하는 값들을 {@code List} 형태로 반환한다.
	 * 해당 경로에 값이 존재하지 않는 경우 Collections.emptyList()를 반환한다.
	 */
	List<String> getValues(String key);

	/**
	 * Data Manager destroy( for example, XML Document)s
	 */
	void destroy();
}
